/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = frfilter.c                                         */
/*  NOTE      = 任务管理                                           */
/*  DATE      = 2014/11/10 by guojq                                */
/*******************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

#include "frcomm.h"
#include "frmem.h"
#include "frlog.h"
#include "frlist.h"
#include "frconfig.h"
#include "frsutl.h"
#include "frame_params.h"
#include "frame.h"

#include "frfilter.h"

#define FILTER_CFG_LINE     256
#define STRING_TCP      "tcp"
#define STRING_UDP      "udp"
#define STRING_ICMP     "icmp"
#define STRING_ANY      "any"

typedef struct __filter_info {
    int i_action;
    u_int src_ip_start;
    u_int src_ip_end;
    u_int dst_ip_start;
    u_int dst_ip_end;
    u_short src_port_start;
    u_short src_port_end;
    u_short dst_port_start;
    u_short dst_port_end;
    u_short us_proto;
    unsigned char arr_mac[APM_MAC_SIZE];
} filter_info;

static Frlist_header *g_p_st_filter_head = NULL;
static pthread_rwlock_t g_filter_rwlock;

/*******************************************************************************
*  FUNC     :  取得链表头
*  ARGS     :  void
*  RTN      :  Frlist_header
*  NOTE     :
*******************************************************************************/
Frlist_header *apm_get_filter_list(void)
{
    return g_p_st_filter_head;
}

/*******************************************************************************
*  FUNC     :  释放链表节点
*  ARGS     :  Frlist_node* node   需要释放的链表节点
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
static void __filter_node_free(Frlist_node* node)
{
    filter_info *p_st_filter = NULL;

    if (node == NULL || node->data == NULL)
        return;
    p_st_filter = (filter_info *)node->data;
    frfree(p_st_filter);
    return;
}

/*******************************************************************************
*  FUNC     :  添加一条filter规则到最后
*  ARGS     :  i_action             当前规则的操作(放行/丢弃)
*           :  src_ip_start         源ip
*           :  src_ip_end           源ip
*           :  dst_ip_start         目标ip
*           :  dst_ip_end           目标ip
*           :  src_port             源端口
*           :  dst_port             目标端口
*           :  us_proto             协议
*           :  arr_mac              mac地址
*  RTN      :  FR_SUCC
*              FR_FAIL
*  NOTE     :  要先做init
*******************************************************************************/
int apm_add_filter(int i_action, unsigned char arr_mac[APM_MAC_SIZE], u_short us_proto
              , u_int src_ip_start, u_int src_ip_end, u_int dst_ip_start, u_int dst_ip_end
              , u_short src_port_start, u_short src_port_end, u_short dst_port_start, u_short dst_port_end)
{
    filter_info *p_st_filter = NULL;
    Frlist_node* p_st_node = NULL;

    p_st_filter = frmalloc(sizeof(filter_info));
    if (p_st_filter == NULL)
    {
        FRLOG_ERROR_DETAIL("frmalloc failed");
        return FR_FAIL;
    }

    p_st_filter->i_action = i_action;
    p_st_filter->src_ip_start = src_ip_start;
    p_st_filter->src_ip_end = src_ip_end;
    p_st_filter->dst_ip_start = dst_ip_start;
    p_st_filter->dst_ip_end = dst_ip_end;
    p_st_filter->src_port_start = src_port_start;
    p_st_filter->src_port_end = src_port_end;
    p_st_filter->dst_port_start = dst_port_start;
    p_st_filter->dst_port_end = dst_port_end;
    p_st_filter->us_proto = us_proto;
    memcpy(p_st_filter->arr_mac, arr_mac, APM_MAC_SIZE);

    p_st_node = frlist_node_create((void *)p_st_filter);
    if (p_st_node == NULL)
    {
        FRLOG_ERROR_DETAIL("frlist_node_create failed");
        frfree(p_st_filter);
        return FR_FAIL;
    }

    pthread_rwlock_wrlock(&g_filter_rwlock);
    frlist_add_tail(g_p_st_filter_head, p_st_node);
    pthread_rwlock_unlock(&g_filter_rwlock);

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  删除所有存在的filter规则
*  ARGS     :
*  RTN      :
*  NOTE     :
*******************************************************************************/
void apm_filter_remove_all(void)
{
    pthread_rwlock_wrlock(&g_filter_rwlock);
    frlist_remove_all(g_p_st_filter_head, __filter_node_free);
    pthread_rwlock_unlock(&g_filter_rwlock);
}

/*******************************************************************************
*  FUNC     :  字符串协议转换成int
*  ARGS     :  p_proto          字符串协议
*  RTN      :  协议号(IPPROTO_TCP/IPPROTO_UDP/IPPROTO_ICMP/FILTER_PROTO_ANY)
*              -1   不支持的协议
*  NOTE     :
*******************************************************************************/
static int __apm_filter_proto2int(char *p_proto)
{
    if (strncasecmp(p_proto, STRING_TCP, strlen(STRING_TCP)) == 0)
        return IPPROTO_TCP;
    else if (strncasecmp(p_proto, STRING_UDP, strlen(STRING_UDP)) == 0)
        return IPPROTO_UDP;
    else if (strncasecmp(p_proto, STRING_ICMP, strlen(STRING_ICMP)) == 0)
        return IPPROTO_ICMP;
    else if (strncasecmp(p_proto, STRING_ANY, strlen(STRING_ANY)) == 0)
        return FILTER_PROTO_ANY;

    return -1;
}

/*******************************************************************************
*  FUNC     :  int转换成字符串协议
*  ARGS     :  i_proto  协议号(IPPROTO_TCP/IPPROTO_UDP/IPPROTO_ICMP/FILTER_PROTO_ANY)
*  RTN      :  tcp/udp/icmp/any
*              其他返回unknown
*  NOTE     :
*******************************************************************************/
static char *__apm_filter_int2proto(int i_proto)
{
    switch (i_proto)
    {
        case IPPROTO_TCP:
            return STRING_TCP;
        case IPPROTO_UDP:
            return STRING_UDP;
        case IPPROTO_ICMP:
            return STRING_ICMP;
        case FILTER_PROTO_ANY:
            return STRING_ANY;
        default:
            break;
    }

    return "unknown";
}

/*******************************************************************************
*  FUNC     :  读一行的filter数据
*  ARGS     :  p_line               一行的数据
*           :  pp_filter_info          记录数据的结构体
*  RTN      :  FR_SUCC
*              FR_FAIL
*  NOTE     :  pp_filter_info外面要释放
*******************************************************************************/
static int __apm_filter_readline(char *p_line, filter_info **pp_filter_info)
{
    filter_info *p_filter_info = NULL;
    char *p_start = p_line;
    char *p_end = NULL;
    char arr_ip[50], arr_proto[20];
    unsigned char arr_mac[APM_MAC_SIZE];
    int i_proto = 0;

    p_filter_info = frmalloc(sizeof(filter_info));
    if (p_filter_info == NULL)
    {
        FRLOG_ERROR_DETAIL("frmalloc failed");
        return FR_FAIL;
    }

    memset(p_filter_info, 0, sizeof(filter_info));

    //action
    p_end = strchr(p_start, ' ');
    if (p_end == NULL)
        goto err;

    p_filter_info->i_action = atoi(p_start);
    p_start = p_end + 1;

    //proto
    p_end = strchr(p_start, ' ');
    if (p_end == NULL)
        goto err;

    snprintf(arr_proto, sizeof(arr_proto)> p_end - p_start+1 ? p_end - p_start+1 : sizeof(arr_proto), "%s", p_start);
    i_proto = __apm_filter_proto2int(arr_proto);
    if (i_proto == -1)
        goto err;
    p_filter_info->us_proto = (u_short)i_proto;

    p_start = p_end + 1;

    //sip
    p_end = strchr(p_start, ' ');
    if (p_end == NULL)
        goto err;

    snprintf(arr_ip, sizeof(arr_ip)> p_end - p_start+1 ? p_end - p_start+1 : sizeof(arr_ip), "%s", p_start);
    iptools_parse_iprange(arr_ip, &p_filter_info->src_ip_start, &p_filter_info->src_ip_end);
    p_start = p_end + 1;

    //dip
    p_end = strchr(p_start, ' ');
    if (p_end == NULL)
        goto err;

    snprintf(arr_ip, sizeof(arr_ip)> p_end - p_start+1 ? p_end - p_start+1 : sizeof(arr_ip), "%s", p_start);
    iptools_parse_iprange(arr_ip, &p_filter_info->dst_ip_start, &p_filter_info->dst_ip_end);
    p_start = p_end + 1;

    //sport
    p_end = strchr(p_start, ' ');
    if (p_end == NULL)
        goto err;

    iptools_parse_portrange(p_start, &p_filter_info->src_port_start, &p_filter_info->src_port_end);
    p_start = p_end + 1;

    //dport
    iptools_parse_portrange(p_start, &p_filter_info->dst_port_start, &p_filter_info->dst_port_end);
    p_end = strchr(p_start, ' ');
    if (p_end == NULL)
    {
        *pp_filter_info = p_filter_info;
        return FR_SUCC;
    }
    //mac
    if (iptools_parse_mac(p_end+1, arr_mac, APM_MAC_SIZE))
        memcpy(p_filter_info->arr_mac, arr_mac, APM_MAC_SIZE);

    *pp_filter_info = p_filter_info;
    return FR_SUCC;

err:
    frfree(p_filter_info);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  从配置文件中读取filter配置
*  ARGS     :
*  RTN      :  FR_SUCC
*              FR_FAIL
*  NOTE     :  适用于第一次读配置文件，运行中更新配置文件
*******************************************************************************/
int apm_filter_load(void)
{
    FILE *fp = NULL;
    char arr_line_tmp[FILTER_CFG_LINE];
    filter_info *p_filter_line = NULL;
    Frlist_header *p_head_tmp = NULL;
    int i_success = 0;

    fp = fopen(APM_CFG_FILENAME_FILTER, "r");
    if (fp == NULL)
    {
        FRLOG_ERROR_DETAIL("open [%s] failed", APM_CFG_FILENAME_FILTER);
        return FR_FAIL;
    }
    p_head_tmp = frlist_create();
    if (p_head_tmp == NULL)
    {
        FRLOG_ERROR_DETAIL("frlist_create failed");
        goto err;
    }

    while (fgets(arr_line_tmp,FILTER_CFG_LINE,fp))
    {
        if (arr_line_tmp[0] == '#')
            continue;
        if (arr_line_tmp[strlen(arr_line_tmp)-1] == '\n')
            arr_line_tmp[strlen(arr_line_tmp)-1] = '\0';

        if (__apm_filter_readline(arr_line_tmp, &p_filter_line) == FR_SUCC)
        {
            Frlist_node* p_st_node = frlist_node_create(p_filter_line);
            if (p_st_node == NULL)
            {
                FRLOG_ERROR_DETAIL("frlist_node_create failed");
                frfree(p_filter_line);
                goto err;
            }
            frlist_add_tail(p_head_tmp, p_st_node);
            i_success = 1;
        }
    }
    if (i_success == 1)
    {
        Frlist_header *p_head_old = g_p_st_filter_head;

        pthread_rwlock_wrlock(&g_filter_rwlock);
        g_p_st_filter_head = p_head_tmp;
        pthread_rwlock_unlock(&g_filter_rwlock);
        frlist_destroy(p_head_old, __filter_node_free);
    }
    else
    {
        Frlist_header *p_head_old = g_p_st_filter_head;
        
        pthread_rwlock_wrlock(&g_filter_rwlock);
        g_p_st_filter_head = NULL;
        pthread_rwlock_unlock(&g_filter_rwlock);
        frlist_destroy(p_head_old, __filter_node_free);
        frlist_destroy(p_head_tmp, __filter_node_free);
    }

    fclose(fp);
    return FR_SUCC;

err:
    frlist_destroy(p_head_tmp, __filter_node_free);
    fclose(fp);
    return FR_FAIL;
}


/*******************************************************************************
*  FUNC     :  比较链表当前节点的情况和当前连接是否一致
*  ARGS     :  Frlist_node* node    链表当前节点
*           :  const void *p_compare_data   此连接的信息
*  RTN      :  1   (不一致)
*              0   (一致)
*  NOTE     :
*******************************************************************************/
static int __apm_run_filter(Frlist_node* node, const void *p_compare_data)
{
    filter_info *p_st_new_filter = NULL;
    filter_info *p_st_list_filter = NULL;
    unsigned char arr_zero[APM_MAC_SIZE] = {'\0'};

    if (node == NULL || p_compare_data == NULL || node->data == NULL)
        return 1;

    p_st_list_filter = (filter_info *)node->data;
    p_st_new_filter = (filter_info *)p_compare_data;
    //比较协议
    if (p_st_list_filter->us_proto != FILTER_PROTO_ANY && p_st_list_filter->us_proto != p_st_new_filter->us_proto)
        return 1;

    //比较mac地址
    if (memcmp(p_st_list_filter->arr_mac, arr_zero, sizeof(arr_zero)))
    {
        if (memcmp(p_st_list_filter->arr_mac, p_st_new_filter->arr_mac, sizeof(p_st_new_filter->arr_mac)))
            return 1;
    }

    //比较源ip地址
    if (p_st_list_filter->src_ip_start != 0 && p_st_list_filter->src_ip_end != 0)
    {
        if (p_st_list_filter->src_ip_start > p_st_new_filter->src_ip_start || p_st_list_filter->src_ip_end < p_st_new_filter->src_ip_start)
            return 1;
    }

    //比较目标ip地址
    if (p_st_list_filter->dst_ip_start != 0 && p_st_list_filter->dst_ip_end != 0)
    {
        if (p_st_list_filter->dst_ip_start > p_st_new_filter->dst_ip_start || p_st_list_filter->dst_ip_end < p_st_new_filter->dst_ip_start)
            return 1;
    }

    //比较源端口
    if (p_st_list_filter->src_port_start != 0 && p_st_list_filter->src_port_end != 0)
    {
        if (p_st_list_filter->src_port_start != p_st_new_filter->src_port_start || p_st_list_filter->src_port_end != p_st_new_filter->src_port_start)
            return 1;
    }

    //比较目标端口
    if (p_st_list_filter->dst_port_start != 0 && p_st_list_filter->dst_port_end != 0)
    {
        if (p_st_list_filter->dst_port_start != p_st_new_filter->dst_port_start || p_st_list_filter->dst_port_end != p_st_new_filter->dst_port_start)
            return 1;
    }

    return 0;
}

/*******************************************************************************
*  FUNC     :  做filter，进行规则过滤
*  ARGS     :  arr_mac              mac地址
*           :  us_proto             协议
*           :  src_ip               源ip
*           :  dst_ip               目标ip
*           :  src_port             源端口
*           :  dst_port             目标端口
*           :  i_default_action     默认规则
*  RTN      :  规则
*  NOTE     :
*******************************************************************************/
int apm_do_filter(unsigned char arr_mac[APM_MAC_SIZE], u_short us_proto
                , u_int src_ip, u_int dst_ip, u_short src_port, u_short dst_port, int i_default_action)
{
    filter_info st_filter_tmp;
    filter_info *p_st_filter_node = NULL;
    Frlist_node *p_st_filter_find = NULL;
    int i_action = 0;

    st_filter_tmp.src_ip_start = src_ip;
    st_filter_tmp.dst_ip_start = dst_ip;
    st_filter_tmp.src_port_start = src_port;
    st_filter_tmp.dst_port_start = dst_port;
    st_filter_tmp.us_proto = us_proto;
    memcpy(st_filter_tmp.arr_mac, arr_mac, APM_MAC_SIZE);

    pthread_rwlock_rdlock(&g_filter_rwlock);

    p_st_filter_find = frlist_find(g_p_st_filter_head, (void *)&st_filter_tmp, __apm_run_filter);
    if (p_st_filter_find == NULL)
    {
        //没找到，做默认规则
        pthread_rwlock_unlock(&g_filter_rwlock);
        return i_default_action;
    }
    p_st_filter_node = (filter_info *)p_st_filter_find->data;
    i_action = p_st_filter_node->i_action;
    pthread_rwlock_unlock(&g_filter_rwlock);

    return i_action;
}

/*******************************************************************************
*  FUNC     :  添加一条准备的规则
*  ARGS     :  i_action             当前规则的操作(放行/丢弃)
*           :  arr_mac              mac地址
*           :  us_proto             协议
*           :  p_src_ip             源ip
*           :  p_dst_ip             目标ip
*           :  p_sport              源端口
*           :  p_dport              目标端口
*  RTN      :  FR_SUCC
*              FR_FAIL
*  NOTE     :  
*******************************************************************************/
int apm_prepare_add(int i_action, char *p_mac, u_short us_proto
              , char *p_src_ip, char *p_dst_ip, char *p_sport, char *p_dport)
{
    FILE *fp = NULL;
    char arr_prepare_file[128];
    int i_file_exist = 1;

    if (p_mac == NULL || p_src_ip == NULL || p_dst_ip == NULL || p_sport == NULL || p_dport == NULL)
        return FR_FAIL;

    snprintf(arr_prepare_file, sizeof(arr_prepare_file), "%s_tmp", APM_CFG_FILENAME_FILTER);

    //判断之前有没有prepare文件
    if (access(arr_prepare_file, 0) != 0)
    {
        //此文件不存在
        char arr_cmd[128];
        
        i_file_exist = 0;
        snprintf(arr_cmd, sizeof(arr_cmd), "cp %s %s", APM_CFG_FILENAME_FILTER, arr_prepare_file);
        system(arr_cmd);
    }

    fp = fopen(arr_prepare_file, "a+");
    if (fp == NULL)
    {
        FRLOG_ERROR_DETAIL("open [%s] failed", arr_prepare_file);
        return FR_FAIL;
    }

    if (i_file_exist)
        //action proto sip dip sport dport mac
        fprintf(fp, "\r\n%d %s %s %s %s %s %s\r\n", i_action, __apm_filter_int2proto(us_proto), p_src_ip, p_dst_ip, p_sport, p_dport, p_mac);
    else
        fprintf(fp, "%d %s %s %s %s %s %s\r\n", i_action, __apm_filter_int2proto(us_proto), p_src_ip, p_dst_ip, p_sport, p_dport, p_mac);

    fclose(fp);
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  比较是否为需要删除的
*  ARGS     :  p_filter_line        比较的结构体
*           :  p_mac                mac地址
*           :  us_proto             协议
*           :  p_src_ip             源ip
*           :  p_dst_ip             目标ip
*           :  p_sport              源端口
*           :  p_dport              目标端口
*  RTN      :  FR_SUCC
*              FR_FAIL
*  NOTE     :  
*******************************************************************************/
static int __apm_del_compare(filter_info *p_filter_line, char *p_mac, u_short us_proto
                          , char *p_src_ip, char *p_dst_ip, char *p_sport, char *p_dport)
{
    u_int sip_start = 0, sip_end = 0;
    u_int dip_start = 0, dip_end = 0;
    u_short src_port_start = 0, src_port_end = 0;
    u_short dst_port_start = 0, dst_port_end = 0;
    unsigned char arr_mac[APM_MAC_SIZE] = {'\0'};
    char arr_zero[APM_MAC_SIZE] = {'\0'};
    
    if (p_filter_line == NULL || p_mac == NULL || p_src_ip == NULL || p_dst_ip == NULL
      || p_sport == NULL || p_dport == NULL)
        return FR_FAIL;
    
    iptools_parse_iprange(p_src_ip, &sip_start, &sip_end);
    iptools_parse_iprange(p_dst_ip, &dip_start, &dip_end);
    iptools_parse_portrange(p_sport, &src_port_start, &src_port_end);
    iptools_parse_portrange(p_dport, &dst_port_start, &dst_port_end);
    
    if (p_filter_line->us_proto != us_proto)
        return FR_FAIL;
    
    if (p_filter_line->src_ip_start != sip_start || p_filter_line->src_ip_end != sip_end)
        return FR_FAIL;
        
    if (p_filter_line->dst_ip_start != dip_start || p_filter_line->dst_ip_end != dip_end)
        return FR_FAIL;
        
    if (p_filter_line->src_port_start != src_port_start || p_filter_line->src_port_end != src_port_end)
        return FR_FAIL;
        
    if (p_filter_line->dst_port_start != dst_port_start || p_filter_line->dst_port_end != dst_port_end)
        return FR_FAIL;
        
    if (iptools_parse_mac(p_mac, arr_mac, APM_MAC_SIZE))
    {
        if (memcmp(arr_mac, p_filter_line->arr_mac, APM_MAC_SIZE))
            return FR_FAIL;
    }
    else if (strcmp(p_mac, "0") != 0 || memcmp(p_filter_line->arr_mac, arr_zero, APM_MAC_SIZE))
        return FR_FAIL;
        
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  删除一条准备的规则
*  ARGS     :  p_mac                mac地址
*           :  us_proto             协议
*           :  p_src_ip             源ip
*           :  p_dst_ip             目标ip
*           :  p_sport              源端口
*           :  p_dport              目标端口
*  RTN      :  FR_SUCC
*              FR_FAIL
*  NOTE     :  
*******************************************************************************/
int apm_prepare_del(char *p_mac, u_short us_proto
                  , char *p_src_ip, char *p_dst_ip, char *p_sport, char *p_dport)
{
    FILE *fp = NULL;
    filter_info *p_filter_line = NULL;
    char arr_line_tmp[FILTER_CFG_LINE];
    char arr_prepare_file[128];
    char *p_new = NULL;
    int i_file_exist = 1;
    int i_malloc = 1024, i_used = 0;

    if (p_mac == NULL || p_src_ip == NULL || p_dst_ip == NULL
      || p_sport == NULL || p_dport == NULL)
        return FR_FAIL;

    snprintf(arr_prepare_file, sizeof(arr_prepare_file), "%s_tmp", APM_CFG_FILENAME_FILTER);

    //判断之前有没有prepare文件
    if (access(arr_prepare_file, 0) != 0)
    {
        //此文件不存在
        pid_t pid_status;
        char arr_cmd[128];
        
        i_file_exist = 0;
        snprintf(arr_cmd, sizeof(arr_cmd), "cp %s %s", APM_CFG_FILENAME_FILTER, arr_prepare_file);
        pid_status = system(arr_cmd);
        if (WEXITSTATUS(pid_status) != 0)
            return FR_FAIL;
    }

    fp = fopen(arr_prepare_file, "r");
    if (fp == NULL)
    {
        FRLOG_ERROR_DETAIL("open [%s] failed", arr_prepare_file);
        return FR_FAIL;
    }
    p_new = frmalloc(i_malloc);
    if (p_new == NULL)
        goto err;

    p_new[0] = '\0';

    while (fgets(arr_line_tmp,FILTER_CFG_LINE,fp))
    {
        if (arr_line_tmp[0] == '#')
            continue;
        if (arr_line_tmp[strlen(arr_line_tmp)-1] == '\n')
        {
            arr_line_tmp[strlen(arr_line_tmp)-1] = '\0';
            if (strlen(arr_line_tmp) > 0 && arr_line_tmp[strlen(arr_line_tmp)-1] == '\r')
                arr_line_tmp[strlen(arr_line_tmp)-1] = '\0';
        }

        if (__apm_filter_readline(arr_line_tmp, &p_filter_line) == FR_SUCC)
        {
            //这一行的数据和需要删除的一致
            if (__apm_del_compare(p_filter_line, p_mac, us_proto, p_src_ip, p_dst_ip, p_sport, p_dport) == FR_SUCC)
            {
                frfree(p_filter_line);
                p_filter_line = NULL;
                continue;
            }
            frfree(p_filter_line);
            p_filter_line = NULL;
        }
        if (i_malloc <= i_used + strlen(arr_line_tmp))
        {
            char *p_remalloc = NULL;
            
            i_malloc += 1024;
            p_remalloc = frmalloc(i_malloc);
            if (p_remalloc == NULL)
                goto err;
            snprintf(p_remalloc, i_malloc, "%s%s", p_new, arr_line_tmp);
            frfree(p_new);
            p_new = p_remalloc;
        }
        else
        {
            strcat(p_new, arr_line_tmp);
            strcat(p_new, "\n");
        }
    }
    
    fclose(fp);
    
    fp = fopen(arr_prepare_file, "w");
    if (fp == NULL)
    {
        frfree(p_new);
        return FR_FAIL;
    }
    fprintf(fp, "%s", p_new);
    
    fclose(fp);
    
    frfree(p_new);
    
    return FR_SUCC;
err:
    fclose(fp);
    if (p_new)
        frfree(p_new);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  提交命令
*  ARGS     :  
*  RTN      :  
*  NOTE     :  
*******************************************************************************/
void apm_filter_commit(void)
{
    char arr_prepare_file[128];
    char arr_cmd[256];
    
    snprintf(arr_prepare_file, sizeof(arr_prepare_file), "%s_tmp", APM_CFG_FILENAME_FILTER);
    
    if (access(arr_prepare_file, 0) != 0)
    {
        apm_filter_load();
        return;
    }
    
    snprintf(arr_cmd, sizeof(arr_cmd), "mv -f %s %s", arr_prepare_file, APM_CFG_FILENAME_FILTER);
    system(arr_cmd);
    apm_filter_load();
    
    return;
}

/*******************************************************************************
*  FUNC     :  回滚命令
*  ARGS     :  
*  RTN      :  
*  NOTE     :  
*******************************************************************************/
void apm_filter_rollback(void)
{
    char arr_prepare_file[128];
    char arr_cmd[256];
    
    snprintf(arr_prepare_file, sizeof(arr_prepare_file), "%s_tmp", APM_CFG_FILENAME_FILTER);
    if (access(arr_prepare_file, 0) != 0)
        return;
    
    snprintf(arr_cmd, sizeof(arr_cmd), "rm -f %s", arr_prepare_file);
    system(arr_cmd);
    return;
}

/*******************************************************************************
*  FUNC     :  格式化显示一条规则
*  ARGS     :  p_st_node             当前节点
*           :  p_outbuff             出力的内容
*           :  ui_buff_size          出力的最大长度
*  RTN      :  
*  NOTE     :  
*******************************************************************************/
static void __filter_node_show(Frlist_node* p_st_node, char *p_outbuff, unsigned int ui_buff_size)
{
    filter_info *p_st_filter = NULL;
    char arr_sip_start[20];
    char arr_sip_end[20];
    char arr_dip_start[20];
    char arr_dip_end[20];

    if (p_st_node == NULL || p_st_node->data == NULL)
        return;
    p_st_filter = (filter_info *)p_st_node->data;
    
    snprintf(arr_sip_start, sizeof(arr_sip_start), "%s", int_ntoa(p_st_filter->src_ip_start));
    snprintf(arr_sip_end, sizeof(arr_sip_end), "%s", int_ntoa(p_st_filter->src_ip_end));
    snprintf(arr_dip_start, sizeof(arr_dip_start), "%s", int_ntoa(p_st_filter->dst_ip_start));
    snprintf(arr_dip_end, sizeof(arr_dip_end), "%s", int_ntoa(p_st_filter->dst_ip_end));
    
    snprintf(p_outbuff, ui_buff_size, "%s %s %s-%s %s-%s %d-%d %d-%d "FRMAC_FMT "\n"
           , p_st_filter->i_action == 1? "accept" : "drop"
           , __apm_filter_int2proto(p_st_filter->us_proto)
           , arr_sip_start
           , arr_sip_end
           , arr_dip_start
           , arr_dip_end
           , p_st_filter->src_port_start, p_st_filter->src_port_end
           , p_st_filter->dst_port_start, p_st_filter->dst_port_end
           , FRMAC_ARG(p_st_filter->arr_mac));
    return;
}

/*******************************************************************************
*  FUNC     :  显示filter所有的内容
*  ARGS     :  pp_out       所有的内容
*  RTN      :  FR_SUCC
*              FR_FAIL
*  NOTE     :  pp_out外面需要释放内存
*******************************************************************************/
int apm_filter_show(char **pp_out)
{
    char *p_out = frmalloc(1024);
    
    if (p_out == NULL)
        return FR_FAIL;
    
    memset(p_out, 0x00, 1024);
    
    frlist_show(g_p_st_filter_head, p_out, 1024, __filter_node_show);
    
    if (*p_out == '\0')
    {
        frfree(p_out);
        return FR_FAIL;
    }
        
    *pp_out = p_out;
    
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  filter模块初始化
*  ARGS     :  void
*  RTN      :  FR_SUCC
*              FR_FAIL
*  NOTE     :
*******************************************************************************/
int apm_filter_init(void)
{
    int i_ret = 0;

    i_ret = pthread_rwlock_init(&g_filter_rwlock, NULL);
    if (i_ret != 0)
    {
        FRLOG_ERROR_DETAIL("pthread_rwlock_init failed");
        return FR_FAIL;
    }

    g_p_st_filter_head = frlist_create();
    if (g_p_st_filter_head == NULL)
    {
        FRLOG_ERROR_DETAIL("frlist create failed");
        return FR_FAIL;
    }

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  filter模块退出
*  ARGS     :
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
void apm_filter_destroy(void)
{
    apm_filter_remove_all();
    pthread_rwlock_destroy(&g_filter_rwlock);
    frlist_destroy(g_p_st_filter_head, __filter_node_free);
}

/*******************************************************************************
*  FUNC     :  filter clear命令
*  ARGS     :
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
void apm_filter_clear(void)
{
    char arr_prepare_file[128];
    char arr_cmd[256];
    
    snprintf(arr_prepare_file, sizeof(arr_prepare_file), "%s_tmp", APM_CFG_FILENAME_FILTER);
    if (access(arr_prepare_file, 0) == 0)
    {
        snprintf(arr_cmd, sizeof(arr_cmd), "rm -f %s", arr_prepare_file);
        system(arr_cmd);
    }
    apm_filter_destroy();
}
